package services

import (
	"crypto/md5"
	"encoding/hex"
	"errors"
	"fmt"
	"github.com/gin-gonic/gin"
	"hitme/go-api/logic/form"
	"hitme/go-api/logic/global"
	"hitme/go-api/logic/repository"
	"hitme/go-api/models"
	"hitme/go-api/modules/api"
	"hitme/go-api/modules/logger"
	"hitme/go-api/modules/utils"
	"runtime"
	"sort"
	"strconv"
	"strings"
)

type orderService struct {}

var OrderService orderService

// Create 创建订单
func (u *orderService) Create (c *gin.Context, req form.OrderCreateReqForm) (*form.OrderCreateRespForm, error) {
	// 获取用户信息
	userInfo := repository.UserRep.FindById(global.UserId)
	if userInfo.Id == 0 {
		return nil, errors.New("用户不存在")
	}

	// 获取图片规格信息
	specInfo := repository.IdcardRep.FindById(req.Id)
	if specInfo.Id == 0 {
		return nil, errors.New("图片规格不存在")
	}

	// 创建订单
	var data models.Order
	//data.Uid = global.UserId
	//data.OrderSn = utils.Generate(time.Now())
	data.SpecId = specInfo.Id
	data.Title = specInfo.SpecName
	data.PhotoWmUrl = req.PhotoWmUrl
	data.OriginPhotoName = req.OriginPhotoName
	data.PicId = req.PicId
	data.Cloth = req.Cloth
	data.Color = req.Color
	isFair, _ := strconv.Atoi(req.IsFair)
	data.IsFair = int8(isFair)
	if req.Cloth != "" {
		data.Price = 2
	} else {
		data.Price = 1
	}
	data.Price = data.Price * 100
	data.Amount = data.Price
	data.Status = 1
	_, err := repository.OrderRep.Create(data)
	if err != nil {
		return nil, errors.New("订单创建失败")
	}

	return &form.OrderCreateRespForm{
		OrderSn: data.OrderSn,
	}, nil
}

// GetList 获取订单列表
func (u *orderService) GetList (c *gin.Context, req form.OrderGetListReqForm) (*form.OrderGetListRespForm, error) {
	// 获取订单列表
	list := repository.OrderRep.GetList(global.UserId)

	var data []form.OrderGetListItem
	for _, val := range list {
		var statusText string
		switch val.Status {
			case 1 :
				statusText = "未支付"
				break
			case 2 :
				statusText = "支付中"
				break
			case 3 :
				statusText = "支付成功"
				break
			case 4 :
				statusText = "支付失败"
				break
			case 5 :
				statusText = "支付成功"
				break
		}

		data = append(data, form.OrderGetListItem{
			OrderSn:    val.OrderSn,
			Status:     val.Status,
			Title:      val.Title,
			PhotoUrl:   val.PhotoUrl,
			Amount:     val.Amount,
			CreatedAt:  val.CreatedAt.Unix(),
			StatusText: statusText,
			PhotoWmUrl: val.PhotoWmUrl,
			Cloth:      val.Cloth,
		})
	}
	if len(list) == 0 {
		data = make([]form.OrderGetListItem, 0)
	}

	return (*form.OrderGetListRespForm)(&data), nil
}

// GetParams 获取支付参数
func (u *orderService) GetParams (c *gin.Context, req form.OrderGetParamsReqForm) (*form.OrderGetParamsRespForm, error) {
	return nil, nil
	
	//// 获取订单详情
	//orderInfo := repository.OrderRep.GetOrderInfo(req.OrderSn)
	//
	//// 获取用户信息
	//userInfo := repository.UserRep.FindById(orderInfo.Uid)
	//
	//// 生成支付参数
	//timeStamp := carbon.Now().Timestamp()
	//
	//// 初始化 BodyMap
	//bm := make(gopay.BodyMap)
	//signType := wechat.SignType_MD5
	//
	//bm.Set("nonce_str", util.GetRandomString(32)).
	//	Set("body", "test").
	//	Set("openid", userInfo.OpenId).
	//	Set("out_trade_no", req.OrderSn).
	//	Set("total_fee", orderInfo.Amount).
	//	Set("spbill_create_ip", c.ClientIP()).
	//	Set("notify_url", global.Settings.WxpayInfo.NotifyUrl).
	//	Set("trade_type", wechat.TradeType_Mini).
	//	Set("sign_type", signType)
	//
	//// 参数 sign ，可单独生成赋值到BodyMap中；也可不传sign参数，client内部会自动获取
	//// 如需单独赋值 sign 参数，需通过下面方法，最后获取sign值并在最后赋值此参数
	//sign := wechat.GetParamSign(global.Settings.WechatInfo.AppID, global.Settings.WxpayInfo.MchId, global.Settings.WxpayInfo.ApiKey, bm)
	//bm.Set("sign", sign)
	//
	//// 微信统一支付
	//client := wechat.Client{
	//	IsProd: true,
	//	DebugSwitch: gopay.DebugOn,
	//}
	//wxRsp,err := client.UnifiedOrder(c, bm)
	//if err != nil {
	//	return nil, err
	//}
	//if wxRsp.ReturnCode == "FAIL" || wxRsp.ResultCode == "FAIL" {
	//	return nil, errors.New("微信支付发起失败")
	//}
	//
	//packages := "prepay_id=" + wxRsp.PrepayId   // 此处的 wxRsp.PrepayId ,统一下单成功后得到
	//paySign := wechat.GetMiniPaySign(global.Settings.WechatInfo.AppID, wxRsp.NonceStr, packages, signType, strconv.Itoa(int(timeStamp)), global.Settings.WxpayInfo.ApiKey)
	//
	//return &form.OrderGetParamsRespForm{
	//	TimeStamp: timeStamp,
	//	NonceStr:  wxRsp.NonceStr,
	//	Package:   packages,
	//	SignType:  signType,
	//	PaySign:   paySign,
	//}, nil
}

// Callback 微信支付回调通知处理
func (u *orderService) Callback (c *gin.Context, req form.OrderCallbackReqForm) (*form.OrderCallbackRespForm, error) {
	return nil, nil
	//if !(req.ReturnCode == "SUCCESS" && req.ResultCode == "SUCCESS") {
	//	fmt.Println(req)
	//	logger.Error("微信支付回调失败:" + req.ReturnCode)
	//	return nil, errors.New("支付回调失败")
	//}
	//
	//logger.Info("微信支付异步通知，HTTP Body:" + utils.JsonMarshal(req))
	//
	//var reqMap map[string]interface{}
	//reqMap = make(map[string]interface{}, 0)
	//reqMap["appid"] = req.Appid
	//reqMap["bank_type"] = req.BankType
	//reqMap["cash_fee"] = req.CashFee
	//reqMap["fee_type"] = req.CashFeeType
	//reqMap["is_subscribe"] = req.IsSubscribe
	//reqMap["mch_id"] = req.MchID
	//reqMap["nonce_str"] = req.NonceStr
	//reqMap["openid"] = req.Openid
	//reqMap["out_trade_no"] = req.OutTradeNo
	//reqMap["result_code"] = req.ResultCode
	//reqMap["return_code"] = req.ReturnCode
	//reqMap["time_end"] = req.TimeEnd
	//reqMap["total_fee"] = req.TotalFee
	//reqMap["trade_type"] = req.TradeType
	//reqMap["transaction_id"] = req.TransactionID
	//
	//// redis锁
	//lockKey := "order-callback-" + req.OutTradeNo
	//lockRes := utils.Lock(lockKey)
	//if !lockRes {
	//	return &form.OrderCallbackRespForm{
	//		ReturnCode: "FAIL",
	//		ReturnMsg: "订单处理中",
	//	}, nil
	//}
	//
	//// 返回解锁
	//defer utils.UnLock(lockKey)
	//
	//// 查找订单信息
	//orderInfo := repository.OrderRep.GetOrderInfoDetail(req.OutTradeNo)
	//if orderInfo.Id == 0 {
	//	return &form.OrderCallbackRespForm{
	//		ReturnCode: "FAIL",
	//		ReturnMsg: "无此订单",
	//	}, nil
	//}
	//// 状态
	//if orderInfo.Status == 3 {
	//	logger.Info("订单已支付，无需重复回调，order_id" + orderInfo.OrderSn)
	//	return &form.OrderCallbackRespForm{
	//		ReturnCode: "SUCCESS",
	//		ReturnMsg: "OK",
	//	}, nil
	//}
	//
	////商户系统对于支付结果通知的内容一定要做签名验证,并校验返回的订单金额是否与商户侧的订单金额一致，防止数据泄漏导致出现“假通知”，造成资金损失
	//if int64(orderInfo.Amount) != req.TotalFee {
	//	return &form.OrderCallbackRespForm{
	//		ReturnCode: "FAIL",
	//		ReturnMsg: "订单金额不正确",
	//	}, nil
	//}
	//
	//logger.Info("订单验证成功，order_id" + orderInfo.OrderSn)
	//
	//specInfo := repository.IdcardRep.FindById(orderInfo.SpecId)
	//if specInfo.Id == 0 {
	//	logger.Info("订单验证成功，无此规格，order_id" + orderInfo.OrderSn)
	//	return &form.OrderCallbackRespForm{
	//		ReturnCode: "FAIL",
	//		ReturnMsg: "无此规格",
	//	}, nil
	//}
	//
	//// 先制作无水印证件照
	//logger.Info("制作无水印证件照，order_id" + orderInfo.OrderSn)
	//makeRes, err := api.IdcardApi.EnvMake(api.IdcardEnvMakeRequest{
	//	ItemId: strconv.Itoa(int(specInfo.ItemId)),
	//	Color:  orderInfo.Color,
	//	Image:  orderInfo.OriginPhotoName,
	//	Beauty: strconv.Itoa(int(orderInfo.IsFair)),
	//});
	//if err != nil {
	//	logger.Info("制作无水印证件照失败，order_id" + orderInfo.OrderSn)
	//	repository.OrderRep.Update(req.OutTradeNo, models.Order{
	//		Status: 5,
	//		FailReason: err.Error(),
	//	})
	//	return &form.OrderCallbackRespForm{
	//		ReturnCode: "SUCCESS",
	//		ReturnMsg: "OK",
	//	}, nil
	//}
	//
	//// 如有换装，则重新制作换装证件照
	//var imageUrl string
	//if orderInfo.Cloth != "" {
	//	logger.Info("制作换装证件照，order_id" + orderInfo.OrderSn)
	//	res, err := api.IdcardApi.ChangeCloth(api.IdcardChangeClothRequest{
	//		PicId:   makeRes.Data.PicId,
	//		Color:   orderInfo.Color,
	//		Clothes: orderInfo.Cloth,
	//	})
	//	if err != nil {
	//		logger.Info("制作换装证件照失败，order_id" + orderInfo.OrderSn)
	//		repository.OrderRep.Update(req.OutTradeNo, models.Order{
	//			Status: 5,
	//			FailReason: err.Error(),
	//		})
	//		return &form.OrderCallbackRespForm{
	//			ReturnCode: "SUCCESS",
	//			ReturnMsg: "OK",
	//		}, nil
	//	}
	//	imageUrl = res.Data.Pic
	//} else {
	//	for _, val := range makeRes.Data.List {
	//		imageUrl = val
	//		break
	//	}
	//}
	//
	//// 上传图片到oss
	//uploadRes, err := api.OssApi.PutObjectRemoteUrl(imageUrl)
	//if err != nil {
	//	logger.Info("上传图片到oss失败，order_id" + orderInfo.OrderSn)
	//	repository.OrderRep.Update(req.OutTradeNo, models.Order{
	//		Status: 5,
	//		FailReason: err.Error(),
	//	})
	//	return &form.OrderCallbackRespForm{
	//		ReturnCode: "SUCCESS",
	//		ReturnMsg: "OK",
	//	}, nil
	//}
	//
	////以下是业务处理 -- 修改订单状态，并请求第三方api获取图片信息
	//logger.Info("更新订单状态，设置为成功，order_id" + orderInfo.OrderSn + "，image_url" + uploadRes.FileUrl)
	//repository.OrderRep.Update(req.OutTradeNo, models.Order{
	//	PhotoUrl: uploadRes.FileUrl,
	//	Status: 3,
	//	PayAt: time.Now(),
	//})
	//
	//return &form.OrderCallbackRespForm{
	//	ReturnCode: "SUCCESS",
	//	ReturnMsg: "OK",
	//}, nil

}

//微信支付签名验证函数
//func wxpayVerifySign(needVerifyM map[string]interface{}, sign string) bool {
//	//方法名 行数
//	pc, _, line, _ := runtime.Caller(0)
//	fc := runtime.FuncForPC(pc)
//
//	WECHAT_API_KEY := global.Settings.WxpayInfo.ApiKey //微信商户key
//	signCalc := wxpayCalcSign(needVerifyM, WECHAT_API_KEY)
//	logger.Info(fc.Name() + strconv.Itoa(line) + "计算出来的sign: " + signCalc)
//	logger.Info(fc.Name() + strconv.Itoa(line) + "微信异步通知sign: " + sign)
//	if sign == signCalc {
//		logger.Info(fc.Name() + strconv.Itoa(line) + "签名校验通过!")
//		return true
//	}
//
//	logger.Error(fc.Name() + strconv.Itoa(line) + "签名校验失败!")
//	return false
//}

//微信支付计算签名的函数
func wxpayCalcSign(mReq map[string]interface{}, key string) (sign string) {
	//方法名 行数
	pc, _, line, _ := runtime.Caller(0)
	fc := runtime.FuncForPC(pc)

	logger.Info(fc.Name() + strconv.Itoa(line) + "微信支付签名计算, API KEY:" + key)
	//STEP 1, 对key进行升序排序.
	sorted_keys := make([]string, 0)
	for k, _ := range mReq {
		sorted_keys = append(sorted_keys, k)
	}

	sort.Strings(sorted_keys)

	//STEP2, 对key=value的键值对用&连接起来，略过空值
	var signStrings string
	for _, k := range sorted_keys {
		value := fmt.Sprintf("%v", mReq[k])
		if value != "" {
			signStrings = signStrings + k + "=" + value + "&"
		}
	}

	//STEP3, 在键值对的最后加上key=API_KEY
	if key != "" {
		signStrings = signStrings + "key=" + key
	}

	//STEP4, 进行MD5签名并且将所有字符转为大写.
	md5Ctx := md5.New()
	md5Ctx.Write(utils.Str2bytes(signStrings))
	cipherStr := md5Ctx.Sum(nil)
	upperSign := strings.ToUpper(hex.EncodeToString(cipherStr))
	return upperSign
}

// RefreshOrder 刷新订单
func (u *orderService) RefreshOrder (c *gin.Context, req form.OrderRefreshOrderReqForm) (*form.OrderRefreshOrderRespForm, error) {
	// 查找订单信息
	orderInfo := repository.OrderRep.GetOrderInfo(req.OrderSn)
	if orderInfo.Id == 0 {
		return nil, errors.New("无此订单")
	}

	// 状态
	if orderInfo.Status != 5 {
		return nil, errors.New("订单不符合刷新要求")
	}

	specInfo := repository.IdcardRep.FindById(orderInfo.SpecId)
	if specInfo.Id == 0 {
		return nil, errors.New("规格不存在，订单刷新失败")
	}

	// 获取无水印证件照
	var imageUrl string
	if orderInfo.IsFair == 1 {
		picId, _ := strconv.Atoi(orderInfo.PicId)
		res, err := api.IdcardApi.ChangeCloth(api.IdcardChangeClothRequest{
			PicId:   uint64(picId),
			Color:   orderInfo.Color,
			Clothes: orderInfo.Cloth,
		})
		if err != nil {
			repository.OrderRep.Update(req.OrderSn, models.Order{
				Status: 5,
				FailReason: err.Error(),
			})
			return nil, errors.New("订单刷新失败")
		}
		imageUrl = res.Data.Pic
	} else {
		res, err := api.IdcardApi.EnvMake(api.IdcardEnvMakeRequest{
			ItemId: strconv.Itoa(int(specInfo.ItemId)),
			Color:  orderInfo.Color,
			Image:  orderInfo.OriginPhotoName,
			Beauty: strconv.Itoa(int(orderInfo.IsFair)),
		});
		if err != nil {
			repository.OrderRep.Update(req.OrderSn, models.Order{
				Status: 5,
				FailReason: err.Error(),
			})
			return nil, errors.New("订单刷新失败")
		}
		for _, val := range res.Data.List {
			imageUrl = val
			break
		}
	}

	//以下是业务处理 -- 修改订单状态，并请求第三方api获取图片信息
	repository.OrderRep.Update(req.OrderSn, models.Order{
		PhotoUrl: imageUrl,
		Status: 3,
	})

	return nil, nil
}